/*
 * Slider.cpp
 *
 *  Created on: 11-12-2010
 *      Author: Przemek
 */

#include "gui/Slider.hpp"
#include "gui/UIManager.hpp"
#include "utils/GLUtils.hpp"

const Dimension Slider::THUMB_SIZE(20, 15);
const float Slider::TRACK_HEIGHT = 5.0f;

Slider::Slider(const RangedValue<int>& value) :
	value(value), thumb(new Button())
{
	setOpaque(false);
	initThumbButton();
}

Slider::Slider(const Range<int>& range) :
	value(range, range.getAverage()), thumb(new Button())
{
	setOpaque(false);
	initThumbButton();
}

void Slider::setValue(int value)
{
	this->value.setValue(value);
}

int Slider::getValue() const
{
	return value.getValue();
}

void Slider::draw(const ClipArea& clipArea)
{
	setThumbPosition();

	UIManager::getInstance().getSliderTrackColor().setGLState();
	int y = (getSize().getHeight() - TRACK_HEIGHT) / 2;
	GLUtils::drawRectangle(Vector(0, y), Dimension(getSize().getWidth(), TRACK_HEIGHT));

	Container::draw(clipArea);
}

void Slider::initThumbButton()
{
	add(thumb);

	thumb->setBounds(geometry::Rectangle(Vector(), THUMB_SIZE));
	thumb->addMouseListener(this);
	thumb->addKeyListener(this);
}

float Slider::getFractionValue(const int x) const
{
	float xPosition = x - THUMB_SIZE.getWidth() / 2.0f;
	if(x <= THUMB_SIZE.getWidth() / 2.0f)
	{
		xPosition = 0.0f;
	}
	else if(x >= getSize().getWidth() - THUMB_SIZE.getWidth() / 2.0f)
	{
		xPosition = getSize().getWidth() - THUMB_SIZE.getWidth();
	}
	return xPosition / (getSize().getWidth() - THUMB_SIZE.getWidth());
}

void Slider::setThumbPosition()
{
	Vector position;
	position.setY((getSize().getHeight() - thumb->getSize().getHeight()) / 2);
	float xPosition = (getSize().getWidth() - THUMB_SIZE.getWidth())
			* value.getFractionalPartInRange();
	position.setX(xPosition);

	thumb->setPosition(position);
}

void Slider::mousePressed(const MouseListener::EventArguments& arguments)
{
	if(arguments.getButton() == MouseListener::EventArguments::LEFT && arguments.getSource() == thumb)
	{
		startDraggingPoint = arguments.getPoint();
	}
	notifyMousePressed(arguments);
}

void Slider::mouseDragged(const MouseListener::EventArguments& arguments)
{
	if(arguments.getButton() == MouseListener::EventArguments::LEFT && arguments.getSource() == thumb)
	{
		const int difference = arguments.getPoint().getX() - startDraggingPoint.getX();
		const int thumbCenterX = thumb->getPosition().getX() + thumb->getSize().getWidth() / 2;
		const float fractionalPart = getFractionValue(difference + thumbCenterX);
		value.setValue(value.getValueFromFractionalPart(fractionalPart));
	}
	notifyMouseDragged(arguments);
}

void Slider::mouseReleased(const MouseListener::EventArguments& arguments)
{
	if(arguments.getSource() == this)
	{
		const float fractionalPart = getFractionValue(arguments.getPoint().getX());
		value.setValue(value.getValueFromFractionalPart(fractionalPart));
	}
	notifyMouseReleased(arguments);
}

void Slider::keyPressed(const KeyListener::EventArguments& arguments)
{
	if(arguments.getKey() == SDLK_LEFT)
	{
		value.changeBy(-1);
	}
	else if(arguments.getKey() == SDLK_RIGHT)
	{
		value.changeBy(1);
	}
	notifyKeyPressed(arguments);
}
